"""
Flask API for Rehabilitation Assessment System

Provides REST API endpoints for:
- Video evaluation
- Template management
- Report retrieval
"""

import os
import yaml
import logging
from datetime import datetime
from flask import Flask, request, jsonify, send_file
from flask_cors import CORS
from werkzeug.utils import secure_filename

from src.core.pose_detector import PoseDetector
from src.core.skeleton_normalizer import SkeletonNormalizer
from src.core.feature_extractor import FeatureExtractor
from src.core.action_segmenter import ActionSegmenter
from src.core.matcher import ActionMatcher
from src.core.report_generator import ReportGenerator
from src.utils.template_builder import TemplateBuilder
from src.utils.video_utils import get_video_frame, frame_to_jpeg, get_video_metadata
import uuid

# Configure logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[logging.StreamHandler()]
)

# Set all src.* loggers to DEBUG
for logger_name in ['src.api.app', 'src.core.matcher', 'src.core.action_segmenter',
                    'src.utils.template_builder']:
    logging.getLogger(logger_name).setLevel(logging.DEBUG)

logger = logging.getLogger(__name__)

# Initialize Flask app
app = Flask(__name__)
CORS(app)

# Load configuration
CONFIG_PATH = os.path.join(os.path.dirname(__file__), '..', '..', 'config.yaml')
with open(CONFIG_PATH, 'r') as f:
    config = yaml.safe_load(f)

# API configuration
API_CONFIG = config.get('api', {})
app.config['MAX_CONTENT_LENGTH'] = API_CONFIG.get('max_video_size', 100) * 1024 * 1024  # MB to bytes

# Initialize components
logger.info("Initializing system components...")

pose_detector = PoseDetector(
    model_complexity=config['pose_detection']['model_complexity'],
    min_detection_confidence=config['pose_detection']['min_detection_confidence'],
    min_tracking_confidence=config['pose_detection']['min_tracking_confidence']
)

skeleton_normalizer = SkeletonNormalizer(
    canvas_size=tuple(config['skeleton']['canvas_size']),
    scale_fill=config['skeleton']['scale_fill'],
    line_thickness=config['skeleton']['line_thickness']
)

feature_extractor = FeatureExtractor(
    model_name=config['feature_extraction']['model_name'],
    device=config['feature_extraction']['device'],
    batch_size=config['feature_extraction']['batch_size']
)

action_segmenter = ActionSegmenter(
    fps=30.0,  # Get from video metadata in practice
    k_high=1.5,  # Balanced threshold to detect actions without over-segmentation
    k_low=0.8,   # Balanced threshold to detect actions without over-segmentation
    L_on=5,      # Moderate frames required to start segment
    L_off=10,    # Moderate frames required to end segment
    min_duration=0.6,  # Minimum 0.6s (18 frames) - allows shorter action segments
    min_silence=0.4,  # Minimum 0.4s (12 frames) between actions
    adaptive=False  # Disable adaptive mode to use fixed parameters
)

action_matcher = ActionMatcher(
    gamma=config['softdtw']['gamma'],
    sigma=config['scoring']['sigma'],
    similarity_weight=config['scoring']['similarity_weight'],
    geometric_weight=config['scoring']['geometric_weight'],
    attribute_weight=config['scoring']['attribute_weight']
)

report_generator = ReportGenerator(
    output_dir=config['paths']['outputs']
)

# Create template_builder with shared instances to ensure consistency
template_builder = TemplateBuilder(
    templates_dir=config['paths']['templates'],
    config=config,
    pose_detector=pose_detector,
    skeleton_normalizer=skeleton_normalizer,
    feature_extractor=feature_extractor
)

logger.info("System components initialized successfully")

# Directory paths
TEMPLATES_DIR = config['paths']['templates']
TEMP_DIR = os.path.join(os.path.dirname(__file__), '..', '..', 'temp')

# Create temp directory if it doesn't exist
os.makedirs(TEMP_DIR, exist_ok=True)

# Video sessions storage
video_sessions = {}


@app.route('/health', methods=['GET'])
def health_check():
    """Health check endpoint."""
    return jsonify({
        'status': 'healthy',
        'timestamp': datetime.now().isoformat()
    })


@app.route('/api/evaluate', methods=['POST'])
def evaluate_video():
    """
    Evaluate a patient video.

    Request JSON:
    {
        "video_path": "path/to/video.mp4",
        "action_type": "raise_leg_left" (optional),
        "session_id": "patient_001" (optional)
    }

    Returns:
    {
        "session_id": "patient_001_2025-11-06",
        "overall_score": 85.5,
        "segments": [...],
        "report_paths": {
            "json": "path/to/report.json",
            "html": "path/to/report.html"
        }
    }
    """
    try:
        data = request.get_json()

        if not data or 'video_path' not in data:
            return jsonify({'error': 'Missing video_path parameter'}), 400

        video_path = data['video_path']
        action_type = data.get('action_type', 'unknown')
        session_id = data.get('session_id', f'session_{datetime.now().strftime("%Y%m%d_%H%M%S")}')

        if not os.path.exists(video_path):
            return jsonify({'error': f'Video file not found: {video_path}'}), 404

        logger.info(f"Processing evaluation request: {video_path}")

        # Step 1: Pose detection
        logger.info("Detecting poses...")
        landmarks_sequence, video_metadata = pose_detector.detect_from_video(video_path)

        if None in landmarks_sequence:
            landmarks_sequence = pose_detector.interpolate_missing_frames(landmarks_sequence)

        # Step 2: Normalize and render
        logger.info("Normalizing and rendering...")
        normalized_sequence, rendered_images = skeleton_normalizer.process_sequence(
            landmarks_sequence, render=True
        )

        # Step 3: Extract features
        logger.info("Extracting features...")
        patient_features = feature_extractor.extract_from_sequence(rendered_images)

        # Step 4: Segment actions
        logger.info("Segmenting actions...")
        segments = action_segmenter.segment_sequence(
            normalized_sequence,
            action_type=action_type or 'default'
        )

        # Step 5: Match and score each segment
        logger.info(f"Scoring {len(segments)} segments...")
        segments_results = []

        # Load template if action type specified
        if action_type != 'unknown':
            try:
                template = template_builder.load_template(action_type)
                template_features = template['features']
                template_landmarks = template['landmarks'].tolist()

                for seg_start, seg_end in segments:
                    # Extract segment data
                    seg_patient_features = patient_features[seg_start:seg_end]
                    seg_patient_landmarks = normalized_sequence[seg_start:seg_end]

                    # Match and score
                    score_result = action_matcher.compute_comprehensive_score(
                        seg_patient_features,
                        template_features,
                        seg_patient_landmarks,
                        template_landmarks,
                        fps=video_metadata.get('fps', 30.0),
                        action_type=action_type
                    )

                    score_result['action_type'] = action_type
                    score_result['frame_range'] = [int(seg_start), int(seg_end)]

                    segments_results.append(score_result)

            except Exception as e:
                logger.warning(f"Could not load template for {action_type}: {e}")
                return jsonify({'error': f'Template not found for action type: {action_type}'}), 404
        else:
            # No template, just segment info
            for seg_start, seg_end in segments:
                segments_results.append({
                    'action_type': 'unknown',
                    'frame_range': [int(seg_start), int(seg_end)],
                    'final_score': 0.0,
                    'similarity_score': 0.0,
                    'geometric_score': 0.0,
                    'attribute_score': 0.0
                })

        # Step 6: Generate report
        logger.info("Generating report...")
        metadata = {
            'video_path': video_path,
            'video_metadata': video_metadata,
            'action_type': action_type
        }

        report_paths = report_generator.generate_full_report(
            session_id,
            segments_results,
            metadata,
            formats=config['report']['formats']
        )

        # Prepare response
        response = {
            'session_id': session_id,
            'overall_score': sum(seg['final_score'] for seg in segments_results) / len(segments_results) if segments_results else 0,
            'num_segments': len(segments_results),
            'report_paths': report_paths,
            'segments': [{
                'segment_id': i,
                'action_type': seg['action_type'],
                'frame_range': seg['frame_range'],
                'final_score': seg['final_score']
            } for i, seg in enumerate(segments_results)]
        }

        logger.info(f"Evaluation completed: {session_id}")

        return jsonify(response), 200

    except Exception as e:
        logger.error(f"Error processing evaluation: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/templates', methods=['GET'])
def list_templates():
    """
    List all available templates.

    Returns:
    {
        "templates": {
            "raise_leg_left": ["expert"],
            "raise_arm": ["expert"],
            ...
        }
    }
    """
    try:
        templates = template_builder.list_templates()
        return jsonify({'templates': templates}), 200

    except Exception as e:
        logger.error(f"Error listing templates: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/template/build', methods=['POST'])
def build_template():
    """
    Build a new template from expert video.

    Request JSON:
    {
        "video_path": "path/to/expert_video.mp4",
        "action_type": "raise_leg_left",
        "template_name": "expert",
        "metadata": {
            "description": "...",
            ...
        }
    }

    Returns:
    {
        "success": true,
        "template": {...}
    }
    """
    try:
        data = request.get_json()

        required_fields = ['video_path', 'action_type']
        for field in required_fields:
            if field not in data:
                return jsonify({'error': f'Missing required field: {field}'}), 400

        video_path = data['video_path']
        action_type = data['action_type']
        template_name = data.get('template_name', 'expert')
        metadata = data.get('metadata', {})

        if not os.path.exists(video_path):
            return jsonify({'error': f'Video file not found: {video_path}'}), 404

        logger.info(f"Building template: {action_type}/{template_name}")

        # Build template
        template = template_builder.build_template(
            video_path,
            action_type,
            template_name,
            metadata
        )

        # Remove large arrays from response
        template_response = {k: v for k, v in template.items() if k not in ['features', 'landmarks']}

        return jsonify({
            'success': True,
            'template': template_response
        }), 200

    except Exception as e:
        logger.error(f"Error building template: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/report/<session_id>', methods=['GET'])
def get_report(session_id):
    """
    Get report for a session.

    Query parameters:
    - format: 'json' or 'html' (default: 'json')

    Returns:
    - JSON: report data
    - HTML: HTML file
    """
    try:
        report_format = request.args.get('format', 'json')

        session_dir = os.path.join(config['paths']['outputs'], session_id)

        if not os.path.exists(session_dir):
            return jsonify({'error': f'Session not found: {session_id}'}), 404

        if report_format == 'json':
            report_path = os.path.join(session_dir, 'report.json')
            if os.path.exists(report_path):
                return send_file(report_path, mimetype='application/json')
            else:
                return jsonify({'error': 'JSON report not found'}), 404

        elif report_format == 'html':
            report_path = os.path.join(session_dir, 'report.html')
            if os.path.exists(report_path):
                return send_file(report_path, mimetype='text/html')
            else:
                return jsonify({'error': 'HTML report not found'}), 404

        else:
            return jsonify({'error': f'Unsupported format: {report_format}'}), 400

    except Exception as e:
        logger.error(f"Error retrieving report: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


# Expert video annotation endpoints

UPLOAD_FOLDER = './uploads/expert_videos'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)


@app.route('/expert/annotator')
def expert_annotator():
    """Serve the expert video annotation UI."""
    return send_file('../web/templates/expert_annotator.html')


@app.route('/api/expert/upload', methods=['POST'])
def upload_expert_video():
    """Upload expert video file."""
    try:
        if 'video' not in request.files:
            return jsonify({'error': 'No video file provided'}), 400

        video_file = request.files['video']

        if video_file.filename == '':
            return jsonify({'error': 'No file selected'}), 400

        # Generate unique video ID
        video_id = str(uuid.uuid4())
        filename = secure_filename(video_file.filename)
        video_path = os.path.join(UPLOAD_FOLDER, f"{video_id}_{filename}")

        # Save video
        video_file.save(video_path)

        # Get metadata
        metadata = get_video_metadata(video_path)

        # Store session
        video_sessions[video_id] = {
            'video_path': video_path,
            'filename': filename,
            'metadata': metadata
        }

        logger.info(f"Uploaded expert video: {video_id}")

        return jsonify({
            'success': True,
            'video_id': video_id,
            'filename': filename,
            'metadata': metadata
        }), 200

    except Exception as e:
        logger.error(f"Error uploading video: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/expert/segment', methods=['POST'])
def segment_expert_video():
    """Automatically segment expert video."""
    try:
        data = request.get_json()

        if 'video_id' not in data:
            return jsonify({'error': 'Missing video_id'}), 400

        video_id = data['video_id']

        if video_id not in video_sessions:
            return jsonify({'error': 'Video session not found'}), 404

        video_path = video_sessions[video_id]['video_path']

        logger.info(f"Segmenting video: {video_id}")

        # Detect poses
        landmarks_seq, video_metadata = pose_detector.detect_from_video(video_path)
        landmarks_seq = pose_detector.interpolate_missing_frames(landmarks_seq)

        # Normalize
        normalized_seq, _ = skeleton_normalizer.process_sequence(landmarks_seq)

        # Segment (optionally guided by hint)
        action_hint = data.get('action_type') if data else None
        segments = action_segmenter.segment_sequence(
            normalized_seq,
            action_type=action_hint or 'default'
        )

        fps = video_metadata.get('fps', 30.0)

        # Format segments
        segments_data = [
            {
                'id': i,
                'start': int(start),
                'end': int(end),
                'duration': round((end - start) / fps, 2),
                'action_type': None  # To be labeled by user
            }
            for i, (start, end) in enumerate(segments)
        ]

        # Store in session
        video_sessions[video_id]['segments'] = segments_data
        video_sessions[video_id]['normalized_seq'] = normalized_seq
        video_sessions[video_id]['landmarks_seq'] = landmarks_seq

        logger.info(f"Detected {len(segments_data)} segments")

        return jsonify({
            'success': True,
            'segments': segments_data,
            'total_frames': len(landmarks_seq),  # 使用实际检测到的帧数
            'fps': fps
        }), 200

    except Exception as e:
        logger.error(f"Error segmenting video: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/expert/label', methods=['POST'])
def save_expert_labels():
    """Save labeled segments and generate templates."""
    try:
        data = request.get_json()

        required = ['video_id', 'segments']
        for field in required:
            if field not in data:
                return jsonify({'error': f'Missing field: {field}'}), 400

        video_id = data['video_id']
        segments = data['segments']  # [{start, end, action_type}, ...]

        if video_id not in video_sessions:
            return jsonify({'error': 'Video session not found'}), 404

        session = video_sessions[video_id]
        video_path = session['video_path']

        # Build segments labels dict
        segments_labels = {
            i: seg['action_type']
            for i, seg in enumerate(segments)
            if seg.get('action_type')
        }

        if not segments_labels:
            return jsonify({'error': 'No segments labeled'}), 400

        logger.info(f"Building templates for {len(segments_labels)} labeled segments")

        # Check if we have cached processing results from /api/expert/segment
        if 'landmarks_seq' in session and 'normalized_seq' in session:
            logger.info("Using cached landmarks and normalized sequences from segmentation step")
            landmarks_seq = session['landmarks_seq']
            normalized_seq = session['normalized_seq']

            # Get video metadata
            import cv2
            cap = cv2.VideoCapture(video_path)
            fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
            frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            cap.release()
            video_metadata = {'fps': fps, 'frame_count': frame_count}

            # Extract features for the full video
            logger.info("Rendering skeletons and extracting features...")
            rendered_imgs = []
            for skeleton in normalized_seq:
                if skeleton is not None:
                    rendered_img = skeleton_normalizer.render_skeleton(skeleton)
                    rendered_imgs.append(rendered_img)
                else:
                    rendered_imgs.append(None)

            features = feature_extractor.extract_from_sequence([img for img in rendered_imgs if img is not None])

            # Re-segment to get the exact same boundaries
            logger.info("Re-segmenting with cached data...")
            segments_result = action_segmenter.segment_sequence(
                normalized_seq,
                action_type='default'
            )

            logger.info(f"Re-segmentation found {len(segments_result)} segments")

            # Build templates for each labeled segment
            templates = {}
            for seg_id, action_type in segments_labels.items():
                if seg_id >= len(segments_result):
                    logger.warning(f"Segment {seg_id} not found")
                    continue

                start, end = segments_result[seg_id]
                logger.info(f"Building template for segment {seg_id} (frames {start}-{end}): {action_type}")

                # Extract segment data
                seg_landmarks = normalized_seq[start:end]
                seg_features = features[start:end] if len(features) >= end else features[start:]

                # Save template
                template_meta = {
                    'fps': video_metadata.get('fps', 30.0),
                    'num_frames': end - start,
                    'video_path': video_path,
                    'segment_range': [int(start), int(end)],
                    'uploaded_by': 'web_ui'
                }

                template_paths = template_builder._save_template_data(
                    action_type=action_type,
                    template_name='expert',
                    landmarks_seq=seg_landmarks,
                    features=seg_features,
                    metadata=template_meta
                )

                templates[action_type] = template_paths
                logger.info(f"✓ Built template: {action_type}/expert (segment {seg_id})")
        else:
            # Fallback: reprocess video (old behavior)
            logger.warning("No cached data found, reprocessing video from scratch")
            templates = template_builder.build_templates_from_segments(
                video_path=video_path,
                segments_labels=segments_labels,
                template_name='expert',
                metadata={'uploaded_by': 'web_ui'}
            )

        logger.info(f"Created {len(templates)} templates")

        return jsonify({
            'success': True,
            'templates': list(templates.keys()),
            'message': f'Successfully created {len(templates)} templates'
        }), 200

    except Exception as e:
        logger.error(f"Error saving labels: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/expert/video/<video_id>/frame/<int:frame_num>', methods=['GET'])
def get_video_frame_image(video_id, frame_num):
    """Get a video frame as JPEG image."""
    try:
        if video_id not in video_sessions:
            return jsonify({'error': 'Video session not found'}), 404

        video_path = video_sessions[video_id]['video_path']

        # Check if thumbnail is requested
        thumbnail = request.args.get('thumbnail', 'false').lower() == 'true'

        if thumbnail:
            # Get thumbnail (faster loading)
            from src.utils.video_utils import create_thumbnail
            jpeg_bytes = create_thumbnail(video_path, frame_num, size=(240, 180))
        else:
            # Get full frame
            frame = get_video_frame(video_path, frame_num)

            if frame is None:
                return jsonify({'error': 'Failed to extract frame'}), 500

            # Convert to JPEG
            jpeg_bytes = frame_to_jpeg(frame)

        if jpeg_bytes is None:
            return jsonify({'error': 'Failed to encode frame'}), 500

        # Return as image
        from io import BytesIO
        return send_file(BytesIO(jpeg_bytes), mimetype='image/jpeg')

    except Exception as e:
        logger.error(f"Error getting frame: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


# ========== 患者视频评估 API ==========

# 患者视频会话存储
patient_video_sessions = {}

@app.route('/api/patient/upload', methods=['POST'])
def upload_patient_video():
    """Upload patient video for assessment."""
    try:
        if 'video' not in request.files:
            return jsonify({'error': 'No video file provided'}), 400

        video_file = request.files['video']
        if video_file.filename == '':
            return jsonify({'error': 'Empty filename'}), 400

        # Save video to temp directory
        video_id = str(uuid.uuid4())
        filename = secure_filename(video_file.filename)
        video_path = os.path.join(TEMP_DIR, f"{video_id}_{filename}")
        video_file.save(video_path)

        # Get video metadata
        metadata = get_video_metadata(video_path)

        # Store session
        patient_video_sessions[video_id] = {
            'video_path': video_path,
            'metadata': metadata,
            'upload_time': datetime.now().isoformat()
        }

        logger.info(f"Patient video uploaded: {video_id} ({metadata['fps']} fps, {metadata['total_frames']} frames)")

        return jsonify({
            'success': True,
            'video_id': video_id,
            'duration': metadata['duration'],
            'fps': metadata['fps'],
            'total_frames': metadata['total_frames']
        })

    except Exception as e:
        logger.error(f"Error uploading patient video: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/patient/video/<video_id>', methods=['GET'])
def serve_patient_video(video_id):
    """Serve patient video for preview."""
    try:
        if video_id not in patient_video_sessions:
            return jsonify({'error': 'Video not found'}), 404

        video_path = patient_video_sessions[video_id]['video_path']
        return send_file(video_path, mimetype='video/mp4')

    except Exception as e:
        logger.error(f"Error serving patient video: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


@app.route('/api/patient/assess', methods=['POST'])
def assess_patient_video():
    """Assess patient video and compare with templates."""
    try:
        data = request.get_json()
        video_id = data.get('video_id')

        if not video_id:
            return jsonify({'error': 'video_id is required'}), 400

        if video_id not in patient_video_sessions:
            return jsonify({'error': 'Video session not found'}), 404

        video_path = patient_video_sessions[video_id]['video_path']
        metadata = patient_video_sessions[video_id]['metadata']

        action_hint = (data or {}).get('action_type')

        logger.info(f"Starting assessment for patient video: {video_id}")

        # Step 1: Pose detection
        logger.info("Step 1: Detecting poses...")
        landmarks_sequence, pose_metadata = pose_detector.detect_from_video(video_path)

        if not landmarks_sequence:
            return jsonify({'error': 'Failed to detect poses in video'}), 500

        # Interpolate missing frames (same as expert template processing)
        missing_count = sum(1 for x in landmarks_sequence if x is None)
        if missing_count > 0:
            logger.info(f"Found {missing_count} missing frames, interpolating...")
            landmarks_sequence = pose_detector.interpolate_missing_frames(landmarks_sequence)

        # Step 2: Normalize skeletons (use same method as expert template)
        logger.info("Step 2: Normalizing skeletons...")
        normalized_skeletons, _ = skeleton_normalizer.process_sequence(landmarks_sequence, render=False)

        # Step 3: Segment actions (use same method as expert template)
        logger.info("Step 3: Segmenting actions...")
        segments = action_segmenter.segment_sequence(
            normalized_skeletons,
            action_type=action_hint or 'default'
        )
        logger.info(f"Detected {len(segments)} action segments")
        for idx, (start, end) in enumerate(segments):
            logger.info(f"  Segment {idx}: frames [{start}, {end}), length={end-start}")

        # Step 4: Render skeletons and extract features for each segment
        logger.info("Step 4: Rendering skeletons and extracting features...")
        segment_features = []
        segment_normalized = []

        for start, end in segments:
            # Get normalized skeletons for this segment
            segment_skeletons = [sk for sk in normalized_skeletons[start:end] if sk is not None]

            if segment_skeletons:
                # Render skeletons to images
                segment_images = []
                for skeleton in segment_skeletons:
                    rendered_image = skeleton_normalizer.render_skeleton(skeleton)
                    segment_images.append(rendered_image)

                # Extract features from rendered images
                features = feature_extractor.extract_from_sequence(segment_images)
                segment_features.append(features)
                segment_normalized.append(segment_skeletons)
            else:
                segment_features.append(None)
                segment_normalized.append(None)

        # Step 5: Match with templates and calculate scores
        logger.info("Step 5: Matching with templates and scoring...")

        # Load all available templates
        try:
            all_templates = template_builder.load_all_templates(template_name='expert')
            if not all_templates:
                return jsonify({'error': 'No templates found. Please create expert templates first.'}), 404
            logger.info(f"Loaded {len(all_templates)} template types")
        except Exception as e:
            logger.error(f"Error loading templates: {e}")
            return jsonify({'error': f'Failed to load templates: {str(e)}'}), 500

        assessment_results = []

        for idx, ((start, end), features, segment_normalized_data) in enumerate(zip(segments, segment_features, segment_normalized)):
            if features is None or segment_normalized_data is None:
                logger.warning(f"Segment {idx} has no valid features or skeletons, skipping")
                continue

            # Get segment landmarks
            segment_landmarks = [lm for lm in landmarks_sequence[start:end] if lm is not None]

            if not segment_landmarks:
                logger.warning(f"Segment {idx} has no valid landmarks, skipping")
                continue

            # Try matching with all templates and find the best match
            best_match = None
            best_score = -1

            for action_type, template in all_templates.items():
                try:
                    template_features = template['features']
                    template_landmarks = template['landmarks']
                    template_meta = template.get('metadata', {})

                    # Log comparison info
                    template_segment_range = template_meta.get('segment_range', 'unknown')
                    template_num_frames = template_meta.get('num_frames', len(template_landmarks))
                    logger.info(f"  Comparing segment {idx} with template '{action_type}':")
                    logger.info(f"    Template: segment_range={template_segment_range}, num_frames={template_num_frames}")
                    logger.info(f"    Patient:  segment_range=[{start}, {end}), num_frames={end-start}")
                    logger.info(f"    Difference: {abs(template_num_frames - (end-start))} frames")

                    # Compute comprehensive score
                    score_result = action_matcher.compute_comprehensive_score(
                        features,
                        template_features,
                        segment_normalized_data,
                        template_landmarks,
                        fps=pose_metadata.get('fps', 30.0),
                        action_type=action_type
                    )

                    final_score = score_result.get('final_score', 0.0)

                    if final_score > best_score:
                        best_score = final_score
                        best_match = {
                            'action_type': action_type,
                            'template_id': template.get('metadata', {}).get('template_name', 'expert'),
                            'score': final_score,
                            'similarity_score': score_result.get('similarity_score', 0.0),
                            'geometric_score': score_result.get('geometric_score', 0.0),
                            'attribute_score': score_result.get('attribute_score', 0.0),
                            'confidence': score_result.get('confidence', {})
                        }

                except Exception as e:
                    logger.warning(f"Error matching segment {idx} with template {action_type}: {e}")
                    continue

            if best_match:
                # Calculate scores as 0-100 percentages
                overall_score = best_match['score']
                confidence_info = best_match.get('confidence', {})

                assessment_results.append({
                    'start_frame': int(start),
                    'end_frame': int(end),
                    'action_type': best_match['action_type'],
                    'matched_template': best_match['template_id'],
                    'score': float(overall_score),
                    'metrics': {
                        'similarity': float(best_match['similarity_score'] / 100),
                        'geometric': float(best_match['geometric_score'] / 100),
                        'attribute': float(best_match['attribute_score'] / 100)
                    },
                    'confidence': {
                        'level': confidence_info.get('level', 'unknown'),
                        'level_text': confidence_info.get('level_text', '未知'),
                        'score': confidence_info.get('score', 0.0),
                        'warnings': confidence_info.get('warnings', [])
                    }
                })
            else:
                logger.warning(f"No template match found for segment {idx}")
                assessment_results.append({
                    'start_frame': int(start),
                    'end_frame': int(end),
                    'action_type': 'unknown',
                    'matched_template': None,
                    'score': 0.0,
                    'metrics': {
                        'similarity': 0.0,
                        'geometric': 0.0,
                        'attribute': 0.0
                    }
                })

        # Calculate overall assessment score
        if assessment_results:
            overall_score = sum(r['score'] for r in assessment_results) / len(assessment_results)
        else:
            overall_score = 0.0

        logger.info(f"Assessment complete. Overall score: {overall_score:.2f}")

        return jsonify({
            'success': True,
            'results': {
                'overall_score': float(overall_score),
                'fps': metadata['fps'],
                'segments': assessment_results
            }
        })

    except Exception as e:
        logger.error(f"Error assessing patient video: {e}", exc_info=True)
        return jsonify({'error': str(e)}), 500


if __name__ == '__main__':
    host = API_CONFIG.get('host', '0.0.0.0')
    port = API_CONFIG.get('port', 5000)
    debug = API_CONFIG.get('debug', False)

    logger.info(f"Starting Flask API server on {host}:{port}")
    app.run(host=host, port=port, debug=debug)
